const Stream = require('node-rtsp-stream');
const { exec, spawn } = require('child_process');
const os = require('os');
const fs = require('fs-extra')
module.exports = app => {
    function startRTSPStream(opts = {}) {
        return new Promise((resolve, reject) => {
            if (!opts.name && !opts.wsPort && !opts.password && !opts.host) return;
            if (!opts.ffmpegOptions) {
                opts.ffmpegOptions = {
                    '-stats': '', // an option with no neccessary value uses a blank string
                    '-r': 25, // options with required values specify the value after the key
                    '-b:v': '4000k',
                    // '-qscale': 1,
                    '-s': '640x480', // shortcut for -s 640x480
                    '-rtsp_transport': 'tcp',
                    '-buffer_size': '1024', // 根据需要调整缓冲区大小
                    '-max_delay': '50000000', // 根据需要调整最大延迟时间
                    // '-threads': '4' // 根据系统核心数和性能调整线程数
                }
            }
            opts.port = opts.port || 554;
            opts.codingStandard = opts.codingStandard || 'h265';
            opts.username = opts.username || 'admin';
            opts.streamUrl = `rtsp://${opts.username}:${opts.password}@${opts.host}:${opts.port}/${opts.codingStandard}/ch1/main/av_stream`;
            try {
                const stream = new Stream({
                    name: opts.name,
                    streamUrl: opts.streamUrl,
                    wsPort: opts.wsPort,
                    ffmpegOptions: opts.ffmpegOptions,
                });
                const streamQueue = app.get('streamQueue') || [];
                streamQueue.push(stream);
                app.set('streamQueue', streamQueue);
                resolve({ type: 'success', message: `${opts.name}开启成功！`, stream });
            } catch (error) {
                reject({ type: 'error', message: `${opts.name}开启失败！`, error });
            }
        })
    }
    function stopRTSPStream(name) {
        return new Promise((resolve, reject) => {
            const streamQueue = app.get('streamQueue') || [];
            if (!streamQueue.length) reject({ type: 'error', message: '没有可关闭的流！' });
            const index = streamQueue.findIndex(item => item.name === name);
            if (index !== -1) {
                try {
                    streamQueue[index].wsServer.close();
                    streamQueue[index].mpeg1Muxer.stream.kill();
                    streamQueue.splice(index, 1);
                    app.set('streamQueue', streamQueue);
                    resolve({ type: 'success', message: `${name}关闭成功！` });
                } catch (error) {
                    reject({ type: 'error', message: `${name}关闭失败！`, error });
                }
            }
        })
    }
    /**
     * 
     * @param {Object} rtsp RTSP流对象
     * @param {string} outputPath 视频输出路径，例如：'/home/user/videos'
     * @param {string} filename 视频文件名，例如：'output.jpg'
     * @returns {Promise<Object>} 返回一个Promise
     */
    function captureRTSPSnapshot(rtsp, outputPath, filename) {
        return new Promise((resolve, reject) => {
            // 使用fs-extra判断路径是否存在，不存在则创建
            fs.ensureDirSync(outputPath);
            // 构建FFmpeg命令行参数
            const command = `ffmpeg -i ${rtsp.streamUrl} -vframes 1 -r 1 ${outputPath}/${filename}`;
            exec(command, (error, stdout, stderr) => {
                if (error) {
                    reject({ type: 'error', message: '截图失败！', error })
                    return;
                }
                // Get the size of the generated snapshot file
                const snapshotFilePath = `${outputPath}/${filename}`;
                const stats = fs.statSync(snapshotFilePath);
                const size = stats.size;
                resolve({ stdout, stderr, size })
            });
        })
    }
    /** 录制
     * @param {Object} rtsp RTSP流对象
     * @param {string} outputPath 视频输出路径，例如：'/home/user/videos'
     * @param {string} filename 视频文件名，例如：'output.mp4'
     * @param {number} duration 录制时长（秒）
     * @returns {Promise<string>} 返回一个Promise，resolve时为录制成功后的视频文件路径
     */
    async function recordRTSPStream(rtsp, data) {
        if (!rtsp || !data.path || !data.name || !data.type || !data.duration) return;
        fs.ensureDirSync(data.path);
        const outputPath = `${data.path}/${data.name}.${data.type}`;

        let videoCodec, audioCodec, videoQuality, audioQuality;

        if (data.type === 'avi') {
            videoCodec = 'libxvid';  // 视频编码器
            audioCodec = 'libmp3lame';  // 音频编码器
            videoQuality = ['-qscale:v', '4'];  // 视频质量
            audioQuality = ['-qscale:a', '4'];  // 音频质量
        } else { // MP4
            videoCodec = 'copy';
            audioCodec = 'aac';
            videoQuality = ['-crf', '23', '-preset', 'medium'];  // 视频质量和编码速度/质量的权衡
            audioQuality = ['-b:a', '128k'];  // 音频比特率
        }

        let args = [
            '-y',
            '-i', rtsp.streamUrl,
            '-c:v', videoCodec,
            ...videoQuality,
            '-c:a', audioCodec,
            ...audioQuality,
            '-t', data.duration.toString(),
            outputPath
        ];

        const ffmpegProcess = spawn('ffmpeg', args, { stdio: 'inherit' });

        const exitPromise = new Promise((resolve, reject) => {
            ffmpegProcess.on('exit', (code, signal) => {
                if (code === 0) {
                    resolve();
                } else {
                    reject(new Error(`FFmpeg exited with code ${code} and signal ${signal}`));
                }
            });
        });

        const timeout = Date.now() + data.duration * 1000;

        await Promise.race([
            exitPromise,
            new Promise((resolve, reject) => {
                const interval = setInterval(() => {
                    if (Date.now() >= timeout) {
                        clearInterval(interval);
                        setTimeout(() => {
                            ffmpegProcess.kill('SIGTERM');
                            resolve();
                        }, data.duration * 1000);
                    }
                }, 1000);
            })
        ]).catch(error => {
            ffmpegProcess.kill('SIGTERM');
            throw error;
        });

        return outputPath;
    }
    return {
        startRTSPStream,
        stopRTSPStream,
        captureRTSPSnapshot,
        recordRTSPStream
    }
}